#pragma once

#include <iostream>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string>
#include <cstring>
#include "log.hpp"

#define SIZE 1024

static void Service(int servicesock, const std::string &ip, const uint16_t &port)
{
    char server_buffer[SIZE];
    while ((true))
    {
        int ret = read(servicesock, server_buffer, sizeof(server_buffer) - 1);
        if (ret > 0)
        {
            server_buffer[ret] = 0;
            printf("[%s:%d]# %s\n", ip.c_str(), port, server_buffer);
        }
        else if (ret == 0)
        {
            logMessage(NORMAL, "server: read EFO, %s:%d.", ip.c_str(), port);
            break;
        }
        else
        {
            logMessage(ERROR, "server: read fail. %d:%s.", errno, strerror(errno));
            break;
        }
        write(servicesock, server_buffer, strlen(server_buffer));
    }
}

class TcpServer
{
    const static int gbacklog = 20;

public:
    TcpServer(uint16_t port, const std::string &ip = "")
        : _port(port), _ip(ip), _listensock(-1)
    {
    }

    ~TcpServer()
    {
        if (_listensock > 0)
            close(_listensock);
    }

    bool ServerInit()
    {
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
        {
            logMessage(ERROR, "server: 创建套接字失败,%d,%s", errno, strerror(errno));
            exit(2);
        }
        logMessage(DEBUG, "server: 创建套接字成功, sock:%d ", _listensock);

        struct sockaddr_in serveraddr;
        bzero(&serveraddr, sizeof serveraddr);
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_port = htons(_port);
        serveraddr.sin_addr.s_addr = _ip.empty()? INADDR_ANY:inet_addr(_ip.c_str());

        if (bind(_listensock, (struct sockaddr *)&serveraddr, sizeof serveraddr) < 0)
        {
            logMessage(ERROR, "server:绑定套接字失败,%d,%s", errno, strerror(errno));
            exit(3);
        }
        logMessage(DEBUG, "绑定套接字成功");

        if (listen(_listensock, gbacklog) < 0)
        {
            logMessage(ERROR, "server:监听失败,%d,%s", errno, strerror(errno));
            exit(4);
        }
        logMessage(DEBUG, "server:监听成功");

        return true;
    }

    void Start()
    {
        signal(SIGCHLD, SIG_IGN);

        while (true)
        {
            struct sockaddr_in clientaddr;
            bzero(&clientaddr, sizeof clientaddr);
            socklen_t len = sizeof clientaddr;
            int serversock = accept(_listensock, (struct sockaddr *)&clientaddr, &len);
            if (serversock < 0)
            {
                logMessage(ERROR, "server:获取连接失败,serversock is %d", serversock);
                exit(5);
            }
            logMessage(DEBUG, "获取连接成功，serversock is %d", serversock);

            uint16_t cilent_port = ntohs(clientaddr.sin_port);
            std::string client_ip = inet_ntoa(clientaddr.sin_addr);
            logMessage(DEBUG, "server:当前连接的客户端,serversock:%d, ip:%s, port:%d", serversock, client_ip.c_str(), cilent_port);

            pid_t pd = fork();
            if (pd == 0)
            {
                close(_listensock);
                Service(serversock, client_ip, cilent_port);
                close(serversock);
                exit(0);
            }
            close(serversock);
        }
    }

private:
    uint16_t _port;
    std::string _ip;
    int _listensock;
};

// #define SIZE 1024

// // 业务函数：服务器用于处理业务，可根据需求自定义
// // 【version1: echo版服务器】：服务端打印从客户端读取到的数据，并将其原封不动返回给客户端
// static void service(int servicesock, const std::string &clientip, const uint16_t &clientport)
// {
//     char server_buffer[SIZE];
//     while (true)
//     {
//         // a、读取客户端发来的数据
//         ssize_t s = read(servicesock, server_buffer, sizeof(server_buffer) - 1);
//         if (s > 0)
//         {
//             server_buffer[s] = '\0'; //\0的ASCII码是0
//             std::cout << clientip << ":" << clientport << "# " << server_buffer << std::endl;
//         }
//         else if (s == 0)
//         {
//             logMessage(NORMAL, "read, %s:%d 退出。", clientip.c_str(), clientport);
//             break;
//         }
//         else
//         {
//             logMessage(ERROR, "read, 读取失败, %d:%s", errno, strerror(errno));
//             break;
//         }

//         // b、将读取到的结果返回
//         write(servicesock, server_buffer, strlen(server_buffer));
//     }
// }

// class TcpServer
// {
// private:
//     const static int gbacklog = 20;//listen中的参数设置

// public:
//     TcpServer(uint16_t port, const std::string& ip="")
//     :_port(port),_ip(ip),_listensock(-1)
//     { }

//     ~TcpServer()
//     { }

//     // 初始化服务器
//     bool ServerInit()
//     {
//         // 1、创建套接字
//         _listensock = socket(AF_INET, SOCK_STREAM, 0); // 这里填入SOCK_STREAM
//         if (_listensock < 0)
//         {
//             logMessage(ERROR, "socket, 创建套接字失败: %s-%d ", errno, strerror(errno));
//             exit(2);
//         }
//         logMessage(DEBUG, "socket, 创建套接字成功,sock: %d", _listensock);

//         // 2、绑定
//         struct sockaddr_in localaddr;
//         bzero(&localaddr, 0);
//         localaddr.sin_family = AF_INET;
//         localaddr.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str()); // IP字节序转换
//         localaddr.sin_port = htons(_port);// port字节序转换
//         if (bind(_listensock, (struct sockaddr *)&localaddr, sizeof localaddr) < 0)
//         {
//             logMessage(ERROR, "bind, 绑定失败，%d:%s", errno, strerror(errno));
//             exit(3);
//         }
//         logMessage(DEBUG, "bind, 绑定成功. ");

//         //3、监听
//         if (listen(_listensock, gbacklog) < 0)
//         {
//             logMessage(ERROR, "listen, 监听失败，%d:%s", errno, strerror(errno));
//             exit(4);
//         }
//         logMessage(DEBUG, "linsten, 监听成功, 初始化套接字完成。");

//         return true;
//     }

//         // 启动服务器
//     void Start()
//     {
//         signal(SIGCHLD, SIG_IGN); // 对SIGCHLD，主动忽略SIGCHLD信号，子进程退出的时候，会自动释放自己的僵尸状态

//         // 网络通讯角度：作为一款网络服务器，永远不退出的！
//         // OS角度：服务器启动-> 进程 -> 常驻进程 -> 永远在内存中存在，除非挂了！
//         while (true)
//         {
//             // 1、获取连接
//             // 1.1、准备工作：用于后续从网络中读取客户端的IP、端口号
//             struct sockaddr_in clientaddr;
//             memset(&clientaddr, 0, sizeof(clientaddr));
//             socklen_t len = sizeof(clientaddr);
//             // 1.2、连接
//             int servicesock = accept(_listensock, (struct sockaddr *)&clientaddr, &len);
//             if (servicesock < 0)
//             {
//                 logMessage(ERROR, "accept, 获取链接失败, servicesock: %d ", servicesock);
//                 continue; // 本次失败了，结束此次循环即可，可下一次重新获取连接
//             }

//             // 2、开始进行通讯服务
//             // 2.1、获取客户端端口号、IP
//             uint16_t client_port = ntohs(clientaddr.sin_port);      // uint16_t htons(uint16_t hostshort);
//             std::string client_ip = inet_ntoa(clientaddr.sin_addr); // char *inet_ntoa(struct in_addr in);
//             logMessage(DEBUG, "accept, 成功获取连接,  servicesock: %d, client: [%s:%d] .", servicesock, client_ip.c_str(), client_port);

//             // 2.2、根据需求处理客户端数据（服务端的业务处理）

//             // ——————————【version2:多进程版本】———————————//
//             pid_t pd = fork();
//             if (pd == 0) // 对子进程：处理业务
//             {
//                 close(_listensock); // 子进程用不到监听套接字，可以关掉（子进程能够继承父进程打开的文件及其fd）
//                 service(servicesock, client_ip, client_port);
//                 exit(0); // 正常退出
//             }
//             // 对父进程：继续循环接收客户端的连接请求
//             close(servicesock); // 父进程用不到accept提供的套接字，可以关掉(对子进程无影响/文件描述符是有限资源，有上限)
//             // ————————————————————————————————————————————//

//         }
//     }

// private:
//     uint16_t _port;//端口号
//     std::string _ip;//IP
//     int _listensock;//套接字
// };
